#pragma once
#include <glm/glm.hpp>

class  IntRect
{
public:
	/// Construct a zero rect.
	IntRect() noexcept :
		left_(0),
		top_(0),
		right_(0),
		bottom_(0)
	{
	}

	/// Construct from minimum and maximum vectors.
	IntRect(const glm::ivec2& min, const glm::ivec2& max) noexcept :
		left_(min.x),
		top_(min.y),
		right_(max.x),
		bottom_(max.y)
	{
	}

	/// Construct from coordinates.
	IntRect(int left, int top, int right, int bottom) noexcept :
		left_(left),
		top_(top),
		right_(right),
		bottom_(bottom)
	{
	}

	/// Construct from an int array.
	explicit IntRect(const int* data) noexcept :
		left_(data[0]),
		top_(data[1]),
		right_(data[2]),
		bottom_(data[3])
	{
	}

	/// Test for equality with another rect.
	bool operator ==(const IntRect& rhs) const
	{
		return left_ == rhs.left_ && top_ == rhs.top_ && right_ == rhs.right_ && bottom_ == rhs.bottom_;
	}

	/// Test for inequality with another rect.
	bool operator !=(const IntRect& rhs) const
	{
		return left_ != rhs.left_ || top_ != rhs.top_ || right_ != rhs.right_ || bottom_ != rhs.bottom_;
	}

	/// Add another rect to this one inplace.
	IntRect& operator +=(const IntRect& rhs)
	{
		left_ += rhs.left_;
		top_ += rhs.top_;
		right_ += rhs.right_;
		bottom_ += rhs.bottom_;
		return *this;
	}

	/// Subtract another rect from this one inplace.
	IntRect& operator -=(const IntRect& rhs)
	{
		left_ -= rhs.left_;
		top_ -= rhs.top_;
		right_ -= rhs.right_;
		bottom_ -= rhs.bottom_;
		return *this;
	}

	/// Divide by scalar inplace.
	IntRect& operator /=(float value)
	{
		left_ = static_cast<int>(left_ / value);
		top_ = static_cast<int>(top_ / value);
		right_ = static_cast<int>(right_ / value);
		bottom_ = static_cast<int>(bottom_ / value);
		return *this;
	}

	/// Multiply by scalar inplace.
	IntRect& operator *=(float value)
	{
		left_ = static_cast<int>(left_ * value);
		top_ = static_cast<int>(top_ * value);
		right_ = static_cast<int>(right_ * value);
		bottom_ = static_cast<int>(bottom_ * value);
		return *this;
	}

	/// Divide by scalar.
	IntRect operator /(float value) const
	{
		return {
			static_cast<int>(left_ / value), static_cast<int>(top_ / value),
			static_cast<int>(right_ / value), static_cast<int>(bottom_ / value)
		};
	}

	/// Multiply by scalar.
	IntRect operator *(float value) const
	{
		return {
			static_cast<int>(left_ * value), static_cast<int>(top_ * value),
			static_cast<int>(right_ * value), static_cast<int>(bottom_ * value)
		};
	}

	/// Add another rect.
	IntRect operator +(const IntRect& rhs) const
	{
		return {
			left_ + rhs.left_, top_ + rhs.top_,
			right_ + rhs.right_, bottom_ + rhs.bottom_
		};
	}

	/// Subtract another rect.
	IntRect operator -(const IntRect& rhs) const
	{
		return {
			left_ - rhs.left_, top_ - rhs.top_,
			right_ - rhs.right_, bottom_ - rhs.bottom_
		};
	}

	/// Return size.
	glm::vec2 Size() const { return glm::vec2(Width(), Height()); }

	/// Return width.
	int Width() const { return right_ - left_; }

	/// Return height.
	int Height() const { return bottom_ - top_; }

	/// Test whether a point is inside.
	bool IsInside(const glm::vec2& point) const
	{
		if (point.x < left_ || point.y < top_ || point.x >= right_ || point.y >= bottom_)
			return false;
		else
			return true;
	}

	/// Return integer data.
	const int* Data() const { return &left_; }

	/// Return left-top corner position.
	glm::vec2 Min() const { return { left_, top_ }; }

	/// Return right-bottom corner position.
	glm::vec2 Max() const { return { right_, bottom_ }; }

	/// Return left coordinate.
	int Left() const { return left_; }

	/// Return top coordinate.
	int Top() const { return top_; }

	/// Return right coordinate.
	int Right() const { return right_; }

	/// Return bottom coordinate.
	int Bottom() const { return bottom_; }

	/// Left coordinate.
	int left_;
	/// Top coordinate.
	int top_;
	/// Right coordinate.
	int right_;
	/// Bottom coordinate.
	int bottom_;

	/// Zero-sized rect.
	static const IntRect ZERO;
};
